package cn.moondev.node.schema;

import java.util.List;

import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;

import cn.moondev.node.impl.NodeChainAdaptor;

/**
 * Node schema解析<BR>
 * 整个实现逻辑比较简单,就是解析xml，设置具体的属性到NodeChainAdaptor类中<BR>
 * 比如：NodeChainAdaptor中有root属性，可以看到parseChain方法就是设置这个属性<BR>
 * NodeChainAdaptor中有nodes属性,是一个map对象，map的key和value均是NodeBeanHandler实例，所以parseBean方法就是解析xml并构造这个map
 * @author scchen
 * @date   Sep 23, 2015
 */
public class NodeChainDefinitionParser implements BeanDefinitionParser {
	
	private static final String NODE_CHAIN_ID = "id";
	private static final String NODE_CHAIN_ROOT = "root";
	private static final String NODE_BEAN_REF = "ref";
	private static final String NODE_BEAN_NEXT = "next";
	private static final String NODE_CHAIN_NODES = "nodes";

	public BeanDefinition parse(Element element, ParserContext parserContext) {
		String chainId = element.getAttribute(NODE_CHAIN_ID);
		AbstractBeanDefinition nodeChainDefinition = parseChain(element,parserContext);
		ManagedMap<Object, Object> nodeMap = parseBean(element,parserContext);
        PropertyValue pv = new PropertyValue(NODE_CHAIN_NODES, nodeMap);
        nodeChainDefinition.getPropertyValues().addPropertyValue(pv);
		parserContext.getRegistry().registerBeanDefinition(chainId, nodeChainDefinition);
		return null;
	}
	
	/**
	 * 解析node:chain标签
	 * @param element
	 * @param parserContext
	 * @return
	 */
	protected AbstractBeanDefinition parseChain(Element element, ParserContext parserContext) {
		String root = element.getAttribute(NODE_CHAIN_ROOT);
		RootBeanDefinition bd = new RootBeanDefinition(NodeChainAdaptor.class);
		// RuntimeBeanReference主要作用是根据bean名称返回bean实例的引用，避免客户端显式获取bean实例。
		RuntimeBeanReference ref = new RuntimeBeanReference(root);
		PropertyValue pv = new PropertyValue(NODE_CHAIN_ROOT, ref);
		bd.getPropertyValues().addPropertyValue(pv);
		bd.setSource(element);
		return bd;
	}
	
	/**
	 * 解析node:bean
	 * @param element
	 * @param parserContext
	 * @return
	 */
	protected ManagedMap<Object, Object> parseBean(Element element,ParserContext parserContext) {
		List<Element> nodeElements = DomUtils.getChildElements(element);
        ManagedMap<Object, Object> nodeMap = new ManagedMap<Object, Object>();
        for(Element node : nodeElements) {
        	 String ref = node.getAttribute(NODE_BEAN_REF);
             String next = node.getAttribute(NODE_BEAN_NEXT);
             /**
              * RuntimeBeanReference已经重写equals和hashCode方法,如果beanName相同,那么表示两个bean相同
              */
             RuntimeBeanReference refBean = new RuntimeBeanReference(ref);
             if(StringUtils.isEmpty(next)) {
            	 nodeMap.put(refBean, null);
             }else{
            	 RuntimeBeanReference nextBean = new RuntimeBeanReference(next);
            	 nodeMap.put(refBean, nextBean);
             }
        }
        return nodeMap;
	}
}
